2006年10月15日
川俣晶の縁側ソフトウェア技術雑記 total 5886 count

.NET Framework 2.0にて、Genericsを使ってHashtableをDictionaryに単純置き換えできないケース

Written By: 川俣 晶連絡先

 あたた。

 こんなところに落とし穴が……。

 .NET Framework 2.0で、System.collections.HashtableをSystem.collections.generics.Dictionaryに単純置き換えできないケースがあります。

インデクサ(itemプロパティ)の動作の違い §

 コレクションに存在しないkeyの値を指定してインデクサでアクセスを行うと(たとえばhashTable[key])、両者の動作は決定的に異なります。

System.collections.Hashtable→nullを返す

System.collections.generics.Dictionary→KeyNotFoundException例外を投げる

 例外のような重い処理を回避するために、System.collections.generics.DictionaryにはTryGetValueメソッドが用意されています。しかし、このメソッドはoutパラメータによって値を受け取る仕様であるため、受け渡し用の変数を宣言しなければなりません。そのため、単純な文字列置換で置き換えることができません。

string val;

bool result = dictionary.TryGetValue(key,out val);

(valに値が入る)

検証ソース (C# 2.0) §

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

namespace ConsoleApplication90

{

    class Program

    {

        static void Main(string[] args)

        {

            Hashtable hashTable = new Hashtable();

            Dictionary<string, string> dictionary = 

                                        new Dictionary<string, string>();

            string key = string.Empty;

            Console.WriteLine("hashTable[key] = {0}", 

                           hashTable[key] == null ? "null" : "not null");

            try

            {

                Console.WriteLine("dictionary[key] = {0}", 

                        dictionary[key] == null ? "null" : "not null");

            }

            catch (KeyNotFoundException)

            {

                Console.WriteLine(

                    "dictionary[key] throwed KeyNotFoundException");

            }

            string val;

            bool result = dictionary.TryGetValue(key,out val);

            Console.WriteLine("dictionary[key] = {0}/{1}", 

                          val == null ? "null" : "not null", result);

        }

    }

}

結果 §

hashTable[key] = null

dictionary[key] throwed KeyNotFoundException

dictionary[key] = null/False

感想 §

 System.collections.Hashtableの仕様の方が優れているような気がします。

 理屈ではSystem.collections.generics.Dictionaryの仕様になることを理解できますが、実際に動くプログラムを書くという意味では、あまり現実的ではないような気がします。

 なぜかといえば。

 コレクションの処理はループの内側の方で繰り返し実行されることが多いような気がしますが、そういうところで例外処理を行うのは重すぎるし、かといってTryGetValueメソッドを使うと表現がまわりくどくなってしまいます。

 うーん、悩ましい。